Only compile activated optional dependencies
authorAlex Crichton <alex@alexcrichton.com>
Fri, 17 Jul 2015 17:05:57 +0000 (10:05 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Fri, 17 Jul 2015 17:05:57 +0000 (10:05 -0700)
Development dependencies are traversed during the resolution process, causing
them to be returned as the list of dependencies for a package in terms of
resolution. The compilation phase would then filter these out depending on the
dependency's transitivity, but this was incorrectly accounted for when the
dependency showed up multiple times in a few lists.

This commit fixes this behavior by updating the filtering logic to ensure that
only activated optional dependencies (those whose feature names are listed) are
compiled.

Closes #1805

src/cargo/ops/cargo_rustc/context.rs
tests/test_cargo_features.rs

index 26b4a14c079b27dbbf798d867bf5f6031eb28c54..2782213ddf32de1ee50cbd36ae8373e9ef553160 100644 (file)
@@ -351,7 +351,6 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
             pkg.dependencies().iter().filter(|d| {
                 d.name() == dep.name()
             }).any(|d| {
-
                 // If this target is a build command, then we only want build
                 // dependencies, otherwise we want everything *other than* build
                 // dependencies.
@@ -364,7 +363,14 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
                                     target.is_example() ||
                                     profile.test;
 
-                is_correct_dep && is_actual_dep
+                // If the dependency is optional, then we're only activating it
+                // if the corresponding feature was activated
+                let activated = !d.is_optional() ||
+                                self.resolve.features(pkg.package_id()).map(|f| {
+                                    f.contains(d.name())
+                                }).unwrap_or(false);
+
+                is_correct_dep && is_actual_dep && activated
             })
         }).filter_map(|pkg| {
             pkg.targets().iter().find(|t| t.is_lib()).map(|t| {
index 3d86dcedf89a9f68731529b2ce323b6bbeb0ecad..33a058f0e32268b288022af8868efd7c117ae452 100644 (file)
@@ -741,3 +741,31 @@ test!(unions_work_with_no_default_features {
     assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
     assert_that(p.cargo("build"), execs().with_status(0).with_stdout(""));
 });
+
+test!(optional_and_dev_dep {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [package]
+            name    = "test"
+            version = "0.1.0"
+            authors = []
+
+            [dependencies]
+            foo = { path = "foo", optional = true }
+            [dev-dependencies]
+            foo = { path = "foo" }
+        "#)
+        .file("src/lib.rs", "")
+        .file("foo/Cargo.toml", r#"
+            [package]
+            name = "foo"
+            version = "0.1.0"
+            authors = []
+        "#)
+        .file("foo/src/lib.rs", "");
+
+    assert_that(p.cargo_process("build"),
+                execs().with_status(0).with_stdout(format!("\
+{compiling} test v0.1.0 ([..])
+", compiling = COMPILING)));
+});